package com.gollum.web.service;


import com.gollum.common.constant.SysConfigConstants;
import com.gollum.common.constant.SystemConstants;
import com.gollum.common.exception.UploadException;
import com.gollum.system.service.SysConfigService;
import io.minio.*;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * mino文件服务
 *
 * @author Herther
 * @createTime 2022年10月26日 21:42:00
 * @since 1.0.0
 */
@Component
@Slf4j
public class MinioService {


    @Autowired
    protected SysConfigService sysConfigService;

    /**
     * 构建MinioClient对象
     * @return OSS
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 21:57
     */
    public MinioClient buildMinioClient(){
        //端点
        String endpoint = sysConfigService.getConfigValue(SysConfigConstants.MINIO_ENDPOINT);
        //令牌
        String accessKey = sysConfigService.getConfigValue(SysConfigConstants.MINIO_ACCESS_KEY);
        //令牌密钥
        String keySecret = sysConfigService.getConfigValue(SysConfigConstants.MINIO_SECRT_KEY);
        // 使用MinIO服务的URL，端口，Access key和Secret key创建一个MinioClient对象
        MinioClient minioClient = MinioClient
                .builder()
                .endpoint(endpoint)
                .credentials(accessKey, keySecret)
                .build();
        return minioClient;
    }




    /**
     * 上传文件输入流
     *
     * @param inputStream 文件输入流
     * @param objectName 上传文件的路径加上文件名 ，例如：test/gollum.png
     * @return 上传后的新地址
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:29
     */
    public String uploadByInputStream(InputStream inputStream,String objectName) {
        try {
            //获取存储桶
            String bucketName  = sysConfigService.getConfigValue(SysConfigConstants.MINIO_BUCKET);
            //minor客户端
            MinioClient minioClient = buildMinioClient();
            //判断minor 的存储桶是否存在
            exitBucketExit(minioClient, bucketName);
            //进行上传
            PutObjectArgs putObj = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(inputStream, inputStream.available(), -1)
                    .build();

           minioClient.putObject(putObj);
           return getUploadPath(objectName,bucketName);
        }catch (IOException e){
            log.error("上传出现异常,错误信息：[{}]", e.getMessage());
            throw new UploadException("上传出现异常，请联系管理员",502,e.toString());
        } catch (ServerException e) {
            log.error("文件服务异常,错误信息：[{}]", e.getMessage());
            throw new UploadException("文件服务异常，请联系管理员",501,e.toString());
        } catch (Exception e){
            log.error("上传出现异常,错误信息：[{}]", e.getMessage());
            throw new UploadException("未知异常，请联系管理员",500,e.toString());
        }
    }

    /**
     * 获取上传路径
     *
     * @param objectName 文件名称 例如：test/abvc.jpg
     * @param bucketName 存储桶名称
     * @return
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/27 22:58
     */
    public String getUploadPath(String objectName,String bucketName){
        //获取上传的地址
        StringBuilder newUrl = new StringBuilder(sysConfigService
                        .getConfigValue(SysConfigConstants.MINIO_ENDPOINT)
                        )
                .append(SystemConstants.BACKSLASH)
                .append(bucketName);
        if (objectName.startsWith(SystemConstants.BACKSLASH)){
            newUrl.append(objectName);
        }else{
            newUrl.append(SystemConstants.BACKSLASH).append(objectName);
        }
        return newUrl.toString();
    }



    /**
     * 上传网络流
     *
     * @param Url 需要上传的来源网络的地址
     * @param objectName 上传文件的路径加上文件名 ，例如：test/gollum.html
     * @return 上传后的地址
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:02
     */
    public String uploadByNetworkStream(String Url,String objectName){
        try {
            URL url = new URL(Url);
            //获取存储桶
            String bucketName  = sysConfigService.getConfigValue(SysConfigConstants.MINIO_BUCKET);
            //minor客户端
            MinioClient minioClient = buildMinioClient();
            //获取输入流
            InputStream inputStream = url.openStream();
            //判断minor 的存储桶是否存在
            exitBucketExit(minioClient, bucketName);
            //进行上传
            PutObjectArgs putObj = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(inputStream, inputStream.available(), -1)
                    .build();
            minioClient.putObject(putObj);
            return getUploadPath(objectName,bucketName);
        } catch (MalformedURLException e) {
            log.error("网络地址流有错误，请确定是否正确，错误内容为[{}]，输入内容为：[{}]", e.getMessage(),Url);
            throw new UploadException("请检查上传的地址是否有问题",500,e.toString());
        } catch (IOException e) {
            log.error("获取输入流失败,错误内容为[{}]，输入内容为：[{}]",e.getMessage(),Url);
            throw new UploadException("请检查上传的地址是否有问题",501,e.toString());
        } catch (ServerException e) {
            log.error("文件服务异常,错误信息：[{}]", e.getMessage());
            throw new UploadException("文件服务异常，请联系管理员",501,e.toString());
        } catch (Exception e){
            log.error("上传出现异常,错误信息：[{}]", e.getMessage());
            throw new UploadException("未知异常，请联系管理员",500,e.toString());
        }
    }

    /**
     * 判断存储桶是否存在 如果不存在则创建
     *
     * @param minioClient 对象存储客户端
     * @param bucketName 存储桶
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:46
     */
    public void exitBucketExit(MinioClient minioClient,String bucketName) {
       try {
           Boolean hasBucketName = minioClient.bucketExists(BucketExistsArgs
                   .builder()
                   .bucket(bucketName)
                   .build());
           if (!hasBucketName){
               //创建存储桶
               minioClient.makeBucket(MakeBucketArgs
                       .builder()
                       .bucket(bucketName)
                       .build());
           }
       }catch (Exception e){
           log.error("校验存储桶：[{}]，是否存在出现异常：[{}]",bucketName,e.getMessage());
           throw new UploadException("上传失败，出现异常了："+ e.getMessage());
       }
    }



    /**
     * 上传文件流
     *
     * @param file 文件流
     * @param objectName 文件名
     * @return 上传后的新地址
     * @auther: Herther
     * @since 1.0.0
     * @date: 2022/10/24 22:29
     */
    public String uploadByFile(File file, String objectName){
        try {
            //获取存储桶
            String bucketName  = sysConfigService.getConfigValue(SysConfigConstants.MINIO_BUCKET);
            //获取mino客户端
            MinioClient minioClient = buildMinioClient();
            exitBucketExit(minioClient,bucketName);
            FileInputStream fileInputStream = new FileInputStream(file);
            //构建上传参数
            PutObjectArgs putObj = PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(fileInputStream, fileInputStream.available(), -1)
                    .build();
            minioClient.putObject(putObj);
            return getUploadPath(objectName,bucketName);
        } catch (IOException e){
            log.error("获取文件输入流失败,错误内容为[{}]，输入内容为：[{}]",e.getMessage());
            throw new UploadException("请检查上传的文件是否有问题",501,e.toString());
        } catch (ServerException e){
            log.error("文件服务异常,错误信息：[{}]", e.getMessage());
            throw new UploadException("文件服务异常，请联系管理员",501,e.toString());
        } catch (Exception e){
            log.error("上传出现异常,错误信息：[{}]", e.getMessage());
            throw new UploadException("未知异常，请联系管理员",500,e.toString());
        }
    }



    ///**
    // * 获得Bucket的策略
    // * @param bucketName
    // * @return
    // * @throws Exception
    // */
    //public static String getBucketPolicy(String bucketName) throws Exception {
    //    return minioClient
    //            .getBucketPolicy(
    //                    GetBucketPolicyArgs
    //                            .builder()
    //                            .bucket(bucketName)
    //                            .build()
    //            );
    //}


    ///**
    // * 获得所有Bucket列表
    // * @return
    // * @throws Exception
    // */
    //public static List<Bucket> getAllBuckets() throws Exception {
    //    return minioClient.listBuckets();
    //}

    ///**
    // * 根据bucketName获取其相关信息
    // * @param bucketName
    // * @return
    // * @throws Exception
    // */
    //public static Optional<Bucket> getBucket(String bucketName) throws Exception {
    //    return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    //}





    //
    ///**
    // * 判断文件是否存在
    // * @param bucketName 存储桶
    // * @param objectName 文件名
    // * @return
    // */
    //public static boolean isObjectExist(String bucketName, String objectName) {
    //    boolean exist = true;
    //    try {
    //        minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
    //    } catch (Exception e) {
    //        log.error("[Minio工具类]>>>> 判断文件是否存在, 异常：", e);
    //        exist = false;
    //    }
    //    return exist;
    //}

    ///**
    // * 判断文件夹是否存在
    // * @param bucketName 存储桶
    // * @param objectName 文件夹名称
    // * @return
    // */
    //public static boolean isFolderExist(String bucketName, String objectName) {
    //    boolean exist = false;
    //    try {
    //        Iterable<Result<Item>> results = minioClient.listObjects(
    //                ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
    //        for (Result<Item> result : results) {
    //            Item item = result.get();
    //            if (item.isDir() && objectName.equals(item.objectName())) {
    //                exist = true;
    //            }
    //        }
    //    } catch (Exception e) {
    //        log.error("[Minio工具类]>>>> 判断文件夹是否存在，异常：", e);
    //        exist = false;
    //    }
    //    return exist;
    //}

    ///**
    // * 根据文件前置查询文件
    // * @param bucketName 存储桶
    // * @param prefix 前缀
    // * @param recursive 是否使用递归查询
    // * @return MinioItem 列表
    // * @throws Exception
    // */
    //public static List<Item> getAllObjectsByPrefix(String bucketName,
    //                                               String prefix,
    //                                               boolean recursive) throws Exception {
    //    List<Item> list = new ArrayList<>();
    //    Iterable<Result<Item>> objectsIterator = minioClient.listObjects(
    //            ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());
    //    if (objectsIterator != null) {
    //        for (Result<Item> o : objectsIterator) {
    //            Item item = o.get();
    //            list.add(item);
    //        }
    //    }
    //    return list;
    //}

    ///**
    // * 获取文件流
    // * @param bucketName 存储桶
    // * @param objectName 文件名
    // * @return 二进制流
    // */
    //public static InputStream getObject(String bucketName, String objectName) throws Exception {
    //    return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    //}

    ///**
    // * 断点下载
    // * @param bucketName 存储桶
    // * @param objectName 文件名称
    // * @param offset 起始字节的位置
    // * @param length 要读取的长度
    // * @return 二进制流
    // */
    //public InputStream getObject(String bucketName, String objectName, long offset, long length)throws Exception {
    //    return minioClient.getObject(
    //            GetObjectArgs.builder()
    //                    .bucket(bucketName)
    //                    .object(objectName)
    //                    .offset(offset)
    //                    .length(length)
    //                    .build());
    //}

    ///**
    // * 获取路径下文件列表
    // * @param bucketName 存储桶
    // * @param prefix 文件名称
    // * @param recursive 是否递归查找，false：模拟文件夹结构查找
    // * @return 二进制流
    // */
    //public static Iterable<Result<Item>> listObjects(String bucketName, String prefix,
    //                                                 boolean recursive) {
    //    return minioClient.listObjects(
    //            ListObjectsArgs.builder()
    //                    .bucket(bucketName)
    //                    .prefix(prefix)
    //                    .recursive(recursive)
    //                    .build());
    //}
    //
    ///**
    // * 使用MultipartFile进行文件上传
    // * @param bucketName 存储桶
    // * @param file 文件名
    // * @param objectName 对象名
    // * @param contentType 类型
    // * @return
    // * @throws Exception
    // */
    //public static ObjectWriteResponse uploadFile(String bucketName, MultipartFile file,
    //                                             String objectName, String contentType) throws Exception {
    //    InputStream inputStream = file.getInputStream();
    //    return minioClient.putObject(
    //            PutObjectArgs.builder()
    //                    .bucket(bucketName)
    //                    .object(objectName)
    //                    .contentType(contentType)
    //                    .stream(inputStream, inputStream.available(), -1)
    //                    .build());
    //}
    //
    ///**
    // * 上传本地文件
    // * @param bucketName 存储桶
    // * @param objectName 对象名称
    // * @param fileName 本地文件路径
    // */
    //public static ObjectWriteResponse uploadFile(String bucketName, String objectName,
    //                                             String fileName) throws Exception {
    //    return minioClient.uploadObject(
    //            UploadObjectArgs.builder()
    //                    .bucket(bucketName)
    //                    .object(objectName)
    //                    .filename(fileName)
    //                    .build());
    //}
    //
    ///**
    // * 创建文件夹或目录
    // * @param bucketName 存储桶
    // * @param objectName 目录路径
    // */
    //public static ObjectWriteResponse createDir(String bucketName, String objectName) throws Exception {
    //    return minioClient.putObject(
    //            PutObjectArgs.builder()
    //                    .bucket(bucketName)
    //                    .object(objectName)
    //                    .stream(new ByteArrayInputStream(new byte[]{}), 0, -1)
    //                    .build());
    //}
    //
    ///**
    // * 获取文件信息, 如果抛出异常则说明文件不存在
    // *
    // * @param bucketName 存储桶
    // * @param objectName 文件名称
    // */
    //public static String getFileStatusInfo(String bucketName, String objectName) throws Exception {
    //    return minioClient.statObject(
    //            StatObjectArgs.builder()
    //                    .bucket(bucketName)
    //                    .object(objectName)
    //                    .build()).toString();
    //}
    //
    ///**
    // * 拷贝文件
    // *
    // * @param bucketName 存储桶
    // * @param objectName 文件名
    // * @param srcBucketName 目标存储桶
    // * @param srcObjectName 目标文件名
    // */
    //public static ObjectWriteResponse copyFile(String bucketName, String objectName,
    //                                           String srcBucketName, String srcObjectName) throws Exception {
    //    return minioClient.copyObject(
    //            CopyObjectArgs.builder()
    //                    .source(CopySource.builder().bucket(bucketName).object(objectName).build())
    //                    .bucket(srcBucketName)
    //                    .object(srcObjectName)
    //                    .build());
    //}
    //
    ///**
    // * 删除文件
    // * @param bucketName 存储桶
    // * @param objectName 文件名称
    // */
    //public static void removeFile(String bucketName, String objectName) throws Exception {
    //    minioClient.removeObject(
    //            RemoveObjectArgs.builder()
    //                    .bucket(bucketName)
    //                    .object(objectName)
    //                    .build());
    //}
    //
    ///**
    // * 批量删除文件
    // * @param bucketName 存储桶
    // * @param keys 需要删除的文件列表
    // * @return
    // */
    //public static void removeFiles(String bucketName, List<String> keys) {
    //    List<DeleteObject> objects = new LinkedList<>();
    //    keys.forEach(s -> {
    //        objects.add(new DeleteObject(s));
    //        try {
    //            removeFile(bucketName, s);
    //        } catch (Exception e) {
    //            log.error("[Minio工具类]>>>> 批量删除文件，异常：", e);
    //        }
    //    });
    //}
    //
    ///**
    // * 获取文件外链
    // * @param bucketName 存储桶
    // * @param objectName 文件名
    // * @param expires 过期时间 <=7 秒 （外链有效时间（单位：秒））
    // * @return url
    // * @throws Exception
    // */
    //public static String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception {
    //    GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build();
    //    return minioClient.getPresignedObjectUrl(args);
    //}
    //
    ///**
    // * 获得文件外链
    // * @param bucketName
    // * @param objectName
    // * @return url
    // * @throws Exception
    // */
    //public static String getPresignedObjectUrl(String bucketName, String objectName) throws Exception {
    //    GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
    //            .bucket(bucketName)
    //            .object(objectName)
    //            .method(Method.GET).build();
    //    return minioClient.getPresignedObjectUrl(args);
    //}
    //
    ///**
    // * 将URLDecoder编码转成UTF8
    // * @param str
    // * @return
    // * @throws UnsupportedEncodingException
    // */
    //public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException {
    //    String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
    //    return URLDecoder.decode(url, "UTF-8");
    //}

}
